package com.glw.sso.platform.web.interceptor;

import com.alibaba.fastjson.JSON;
import com.glw.sso.platform.common.constant.CacheKeyEnum;
import com.glw.sso.platform.common.constant.GlobalResponseNo;
import com.glw.sso.platform.common.response.Response;
import com.glw.sso.platform.common.util.LoginContext;
import com.glw.sso.platform.common.util.LoginInfo;
import com.glw.sso.platform.domain.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;

@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Resource
    RedisTemplate<String, Object> redisTemplate;

    @Value("${login.token-field-name}")
    private String TOKEN_FIELD_NAME = "";

    @Value("${login.debug}")
    private String DEBUG = "";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("登录拦截开始 {}", request.getRequestURI());

        if (!StringUtils.isEmpty(DEBUG)) {
            LoginInfo loginInfo = new LoginInfo();
            loginInfo.setPin(DEBUG);
            loginInfo.setUsername("test");
            loginInfo.setToken("test");
            LoginContext.checkin(loginInfo);
            log.info("DEBUG模式开启设置默认登录用户:{}", DEBUG);
            return true;
        }

        return doHandle(request, response);
    }

    private boolean doHandle(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Optional<String> tokenOptional = getToken(request);

        if (!tokenOptional.isPresent()) {
            log.info("获取{}失败", TOKEN_FIELD_NAME);
            cutoff(response);
            return false;
        }

        String token = tokenOptional.get();

        String key = CacheKeyEnum.UserInfoStringCache.key(token);
        if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
            log.info("无效{}:{} | key:{}", TOKEN_FIELD_NAME, token, key);
            cutoff(response);
            return false;
        }

        User loginUserInfo = (User) redisTemplate.opsForValue().get(key);
        if (loginUserInfo == null) {
            log.info("拉取登录用户信息失败{}:{} | key:{}", TOKEN_FIELD_NAME, token, key);
            cutoff(response);
            return false;
        }

        LoginInfo loginInfo = new LoginInfo();
        loginInfo.setPin(loginUserInfo.getPin());
        loginInfo.setUsername(loginUserInfo.getUsername());
        loginInfo.setToken(token);
        LoginContext.checkin(loginInfo);

        log.info("登录验证通过 {}:{}", LoginContext.getCurrentLoginUser(), token);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        LoginContext.checkout();
    }

    private Optional<String> getToken(HttpServletRequest request) {
        String token4Header = request.getHeader(TOKEN_FIELD_NAME);
        if (!StringUtils.isEmpty(token4Header)) {
            return Optional.of(token4Header);
        }

        String token4Request = request.getParameter(TOKEN_FIELD_NAME);
        if (!StringUtils.isEmpty(token4Request)) {
            return Optional.of(token4Request);
        }

        Object token4Session = request.getSession().getAttribute(TOKEN_FIELD_NAME);
        if (token4Session != null) {
            return Optional.of(token4Session.toString());
        }

        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            Optional<Cookie> token4Cookie = Arrays.stream(cookies)
                    .filter(cookie -> cookie.getName().equals(TOKEN_FIELD_NAME))
                    .findFirst();
            if (token4Cookie.isPresent()) {
                return Optional.of(token4Cookie.get().getValue());
            }
        }

        return Optional.empty();
    }

    private void cutoff(HttpServletResponse response) throws IOException {
        response.getWriter().print(JSON.toJSONString(Response.failed(GlobalResponseNo.UN_LOGIN, "un login")));
    }
}